package lol.clann.bukkit.pluginboot.devtool;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.tuple.MutablePair;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;

/**
 * 本人做全版本兼容时,合并几个mapping使用的工具
 *
 * @author pyz
 * @date 2018/10/7 下午2:35
 */
public class MappingGenerator {
    Map<String, Node> byCompile = new HashMap<>();
    Map<String, Node> byRuntime = new HashMap<>();
    private Path cl = Paths.get("/Users/admin/MC/bukkit/plugins/MCFramwork/spigot/mapping/bukkit-1.12.2-cl.csrg");
    private Path member = Paths.get("/Users/admin/MC/bukkit/plugins/MCFramwork/spigot/mapping/bukkit-1.12.2-members.csrg");
    private Path mcp = Paths.get("/Users/admin/MC/bukkit/plugins/MCFramwork/spigot/mapping/mcp-notch.srg");
    private MappingGenerator() throws Exception {
        List<String> lines = null;

        lines = Files.readAllLines(cl, StandardCharsets.UTF_8);
        for (String line : lines) {
            String[] ss = line.split(" ");
            Node node = new Node().setType(1).setRuntime(ss[1]).setCompile(ss[0]);
            byCompile.put(node.getCompile(), node);
            byRuntime.put(node.getRuntime(), node);
        }

        lines = Files.readAllLines(member, StandardCharsets.UTF_8);
        for (String line : lines) {
            String[] ss = line.split(" ");
            if (ss.length == 3) {
                // 字段
                Node node = byRuntime.get(ss[0]);
                if (node == null) {
                    node = new Node().setType(2).setCompile(ss[0].replace("net/minecraft/server/", "")).setRuntime(ss[0]);
                    byRuntime.put(node.getRuntime(), node);
                    byCompile.put(node.getCompile(), node);
                }
                Node fd = new Node().setType(2).setCompile(node.getCompile() + "/" + ss[1]).setRuntime(node.getRuntime() + "/" + ss[2]);
                byCompile.put(fd.getCompile(), fd);
                byRuntime.put(fd.getRuntime(), fd);
            } else if (ss.length == 4) {
                // 方法
                Node node = byRuntime.get(ss[0]);
                String compilePart = runtimeToCompile(ss[2]);
                Node md = new Node().setType(3).setCompile(node.getCompile() + "/" + ss[1] + compilePart).setRuntime(node.getRuntime() + "/" + ss[3] + ss[2]);
                byCompile.put(md.getCompile(), md);
                byRuntime.put(md.getRuntime(), md);
            }
        }

        lines = Files.readAllLines(mcp, StandardCharsets.UTF_8);
        for (String line : lines) {
            String[] ss = line.split(" ");
            Node node = new Node();
            if (ss[0].equals("CL:")) {
                node = byCompile.get(ss[2]);
                if (node != null) {
                    node.setDev(ss[1]);
                }
            } else if (ss[0].equals("FD:")) {
                node = byCompile.get(ss[2]);
                if (node != null) {
                    node.setDev(ss[1]);
                }
            } else if (ss[0].equals("MD:")) {
                node = byCompile.get(ss[3] + ss[4]);
                if (node != null) {
                    node.setDev(ss[1] + ss[2]);
                }
            }
        }
        ArrayList<Node> list = new ArrayList<>(byCompile.values());
        Comparator<Integer> c1 = Comparator.comparingInt(l -> l);
        list.sort((l, r) -> {
            int result = c1.compare(l.getType(), r.getType());
            if (result != 0) {
                return result;
            }
            return l.getRuntime().compareTo(r.getRuntime());
        });
        for (Node node : list) {
            System.out.println(node.toString());
        }
    }

    public static void main(String[] args) throws Exception {
        new MappingGenerator();
    }

    private String runtimeToCompile(String signature) {
        try {
            String params = signature.substring(1, signature.indexOf(")"));
            MutablePair<String, Integer> param = MutablePair.of(params, 0);
            replace(param);
            String returnType = signature.substring(signature.indexOf(")") + 1);
            Node node = byRuntime.get(returnType);
            if (node != null) {
                returnType = node.getCompile();
            }
            return "(" + param.getLeft() + ")" + returnType;
        } catch (Throwable e) {
            throw new RuntimeException(signature, e);
        }
    }

    private void replace(MutablePair<String, Integer> pair) {
        if (pair.getRight() == -1) {
            return;
        }
        String param = pair.getLeft();
        int index = pair.getRight();
        int start = param.indexOf("L", index) + 1;
        int end = param.indexOf(";", start);
        if (start == 0) {
            return;
        }
        String part = param.substring(start, end);
        Node node = byRuntime.get(part);
        if (node != null) {
            param = param.replace(part, node.getCompile());
        }
        pair.setRight(param.indexOf(";", start));
        pair.setLeft(param);
        replace(pair);
    }


    @Setter
    @Getter
    private static class Node {
        private String runtime;
        private String compile;
        private String dev;
        /**
         * 1:Cl
         * 2:FD
         * 3:MD
         */
        private int type;

        @Override
        public String toString() {
            return type + " " + compile + " " + runtime + " " + dev;
        }
    }
}
